#include "list.h"
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

#define LIST_LOG_INFO(...) // printf(__VA_ARGS__)

int clist_delete_node(List *plist, Node *pnode)
{
    CLIST_CHECK_PTR_NULL(pnode);

    plist->user_hooks.user_data_free(pnode->data);   // 释放用户分配的数据
    free(pnode->data);                    // 释放节点数据空间
    free(pnode);                          // 释放节点
    pnode = NULL;

    return CLIST_OK;
}

Node * clist_create_node(List *plist, void *data, size_t size)
{
    if (!data)
    {
        return NULL;
    }

    Node *pnode = NULL;
    pnode = (Node *)malloc(sizeof(Node));
    if (!pnode)
    {
        return NULL;
    }
    pnode->data = malloc(size);
    if (!pnode->data)
    {
        free(pnode);
        return NULL;
    }
    memcpy(pnode->data, data, size);
    plist->user_hooks.user_data_free(data);
    pnode->next = NULL;

    return pnode;
}

void clist_delete_list(List *plist)
{
    if (plist == NULL)
        return ;

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = plist->head)
    {
        plist->head = plist->head->next;
        plist->delete_node(plist, pnode);
    }
    free(plist);
    plist = NULL;
}

int clist_node_add(List *plist, void *data, size_t size)
{
    CLIST_CHECK_PTR_NULL(data);
    CLIST_CHECK_PTR_NULL(plist);

    Node *pnode = plist->create_node(plist, data, size);
    if (pnode == NULL) {
        return CLIST_ERR_PTR_NULL;
    }

    if (NULL == plist->head)
    {
        plist->head = pnode;
        plist->tail = pnode;
    }
    else
    {
        plist->tail->next = pnode;
        plist->tail = pnode;
    }
    plist->size++;

    return CLIST_OK;
}

int clist_node_del(List *plist)
{
    CLIST_CHECK_PTR_NULL(plist);

    if (plist->size == 1)
    {
        plist->delete_node(plist, plist->tail);
        plist->head = NULL;
        plist->tail = NULL;
    }
    else
    {
        Node *pnode = plist->clist_get_data_by_index(plist, plist->size - 1);
        if (!pnode)
        {
            return CLIST_ERR_PTR_NULL;
        }
        plist->delete_node(plist, plist->tail);
        plist->tail = pnode;
        plist->tail->next = NULL;
    }
    plist->size--;

    return CLIST_OK;
}

int clist_node_del_by_data(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
    CLIST_CHECK_PTR_NULL(plist);
    CLIST_CHECK_PTR_NULL(data);

    if (plist->size == 1 && p_traverse(plist->head->data, data) == 0)
    {
        if (plist->node_del(plist) != CLIST_OK)
        {
            return CLIST_ERR_OPERATION;
        }
    }
    else
    {
        Node *pnode = plist->head;
        for (Node *pprior = NULL; pnode != NULL; pprior = pnode, pnode = pnode->next)
        {
            if (p_traverse(pnode->data, data) == 0)
            {
                pprior->next = pnode->next;
                if (pnode == plist->tail)
                {
                    plist->tail = pprior;
                }

                plist->delete_node(plist, pnode);
                plist->size--;
            }
        }
    }

    return CLIST_OK;
}

void * clist_get_data_by_index(List *plist, int index)
{
    if (!plist || !plist->head || index < 1 || index > plist->size)
    {
        return NULL;
    }

    Node *pnode = plist->head;
    for (int i = 1; i < index; i++)
    {
        pnode = pnode->next;
    }

    return pnode->data;
}

void * clist_get_data_by_data(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
    if (!plist || !data)
    {
        return NULL;
    }

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = pnode->next)
    {
        if (p_traverse(pnode->data, data) == 0)
        {
            return pnode->data;
        }
    }

    return NULL;
}

int clist_get_index_by_data(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
    CLIST_CHECK_PTR_NULL(plist);
    CLIST_CHECK_PTR_NULL(data);

    Node *pnode = plist->head;
    for (int index = 1; pnode != NULL; index++, pnode = pnode->next)
    {
        if (p_traverse(pnode->data, data) == 0)
        {
            return index;
        }
    }

    return 0;
}

int clist_traverse_list(List *plist, void *data, int (*p_traverse)(void *node_data, void *data))
{
    CLIST_CHECK_PTR_NULL(plist);

    Node *pnode = plist->head;
    for (; pnode != NULL; pnode = pnode->next)
    {
        p_traverse(pnode->data, data);
    }

    return CLIST_OK;
}


List * clist_new_list(clist_user_hooks_t *user_hooks)
{
    if (user_hooks == NULL || user_hooks->user_data_free == NULL || user_hooks->node_compare == NULL)
        return NULL;

    List *plist = (List *)malloc(sizeof(List));
    if (plist == NULL) {
        return NULL;
    }

    plist->head = NULL;
    plist->tail = NULL;
    plist->size = 0;

    plist->user_hooks.user_data_free = user_hooks->user_data_free;
    plist->user_hooks.node_compare = user_hooks->node_compare;

    plist->create_node = clist_create_node;
    plist->delete_node = clist_delete_node;

    plist->clist_delete_list = clist_delete_list;
    plist->node_add = clist_node_add;
    plist->node_del = clist_node_del;
    plist->node_del_by_data = clist_node_del_by_data;
    plist->clist_get_data_by_data = clist_get_data_by_data;
    plist->clist_get_data_by_index = clist_get_data_by_index;
    plist->clist_get_index_by_data = clist_get_index_by_data;
    plist->clist_traverse_list = clist_traverse_list;

    return plist;
}